package com.cloudweb.oa.service.impl;

import cn.js.fan.db.SQLFilter;
import cn.js.fan.util.DateUtil;
import cn.js.fan.util.StrUtil;
import com.cloudweb.oa.entity.Doc;
import com.cloudweb.oa.repository.DocRepository;
import com.cloudweb.oa.service.DocEsService;
import com.cloudweb.oa.utils.ConstUtil;
import com.cloudweb.oa.utils.SpringUtil;
import com.redmoon.oa.visual.FormDAO;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.metrics.ParsedAvg;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@Service
@ConditionalOnProperty(name = "elasticsearch.enabled", matchIfMissing = false, havingValue = "true")
public class DocEsServiceImpl implements DocEsService {
    @Autowired
    private DocRepository docRepository;

    @Autowired
    private ElasticsearchRestTemplate template;

    @Override
    public void index(java.util.Date beginDate) {
        String format = "yyyy-MM-dd HH:mm:ss";
        String bd = DateUtil.format(beginDate, format);
        String sql = "select id from ft_document where create_date>=" + SQLFilter.getDateStr(bd, format) +
                " and status=" + ConstUtil.FILEARK_EXAMINE_PASS + " order by id asc";

        FormDAO dao = new FormDAO();
        List<FormDAO> list = dao.selectList(ConstUtil.FILEARK_DOC, sql);
        for (FormDAO fdao : list) {
            /*Optional<Doc> optDoc = docRepository.findById(fdao.getId());
            if (optDoc.isPresent()) {
                Doc doc = optDoc.get();
                ...
            }*/
            // 更新索引时不需要删除
            // docRepository.deleteById(fdao.getId());

            Doc doc = new Doc();
            doc.setId(fdao.getId());
            doc.setTitle(fdao.getFieldValue("title"));
            doc.setContent(fdao.getFieldValue("content"));
            doc.setDirCode(fdao.getFieldValue("dir_code"));
            doc.setUserName(fdao.getFieldValue("user_name"));
            //把文档写入索引库
            docRepository.save(doc);
        }
    }

    //查询所有文档
    @Override
    public void findAll() throws Exception {
        Iterable<Doc> docs = docRepository.findAll();
        for (Doc doc : docs) {
            System.out.println(doc);
        }
    }

    @Override
    public void deleteAll() {
        docRepository.deleteAll();
    }

    //根据ID查询
    public void findById() throws Exception {
        Doc doc = template.get("14", Doc.class);
        System.out.println(doc);
    }

    //匹配标题，精准匹配
    public void findByTitle() throws Exception {
        List<Doc> list = docRepository.findByTitle("标题");
        for (Doc doc : list) {
            System.out.println(doc);
        }
    }

    //匹配标题或者内容
    public void findByTitleOrContent() throws Exception {
        Pageable pageable = PageRequest.of(1, 5);
        List<Doc> docs = docRepository.findByTitleOrContent("maven", "内容", pageable);
        for (Doc doc : docs) {
            System.out.println(doc);
        }
    }

    @Override
    public Map<String, Object> search(String dirCode, String keyword, int page, int pageSize, boolean isHighlight) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchQuery("title", keyword))
                .should(QueryBuilders.matchQuery("content", keyword));
        if (!StrUtil.isEmpty(dirCode)) {
            // matchQuery搜索时会分词，而term不分词
            BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
            // boolQueryBuilder = boolBuilder.must(QueryBuilders.matchQuery("dirCode", dirCode)).must(boolQueryBuilder);
            boolQueryBuilder = boolBuilder.must(QueryBuilders.termQuery("dirCode", dirCode)).must(boolQueryBuilder);
        }
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder = nativeSearchQueryBuilder
                .withQuery(boolQueryBuilder)
                // 注意页码从 0 开始
                .withPageable(PageRequest.of(page-1, pageSize));
        /*nativeSearchQueryBuilder = nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"))
                .withPageable(PageRequest.of(page, pageSize));*/
        nativeSearchQueryBuilder = nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));

        if (isHighlight) {
            nativeSearchQueryBuilder = nativeSearchQueryBuilder.withHighlightFields(
                    new HighlightBuilder.Field("title").preTags("<span style='color:red'>").postTags("</span>"),
                    new HighlightBuilder.Field("content").preTags("<span style='color:red'>").postTags("</span>")
            );
        }

        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();

        SearchHits<Doc> search = template.search(searchQuery, Doc.class);
        // 得到查询结果返回的内容
        List<SearchHit<Doc>> searchHits = search.getSearchHits();
        // 设置一个需要返回的实体类集合
        List<Doc> docs = new ArrayList<>();
        // 遍历返回的内容进行处理
        for (SearchHit<Doc> searchHit : searchHits) {
            if (isHighlight) {
                // 高亮的内容
                Map<String, List<String>> highLightFields = searchHit.getHighlightFields();
                // 将高亮的内容填充到content中
                searchHit.getContent().setTitle(highLightFields.get("title") == null ? searchHit.getContent().getTitle() : highLightFields.get("title").get(0));
                String content = highLightFields.get("content") == null ? searchHit.getContent().getContent() : highLightFields.get("content").get(0);
                if (highLightFields.get("content") == null) {
                    HttpServletRequest request = SpringUtil.getRequest();
                    content = StrUtil.getAbstract(request, content, 400);
                }

                int p = content.indexOf("<");
                int q = content.indexOf(">");
                if ((p == -1 && q > 0) || p > q) {
                    content = content.substring(q + 1);
                }
                searchHit.getContent().setContent(content);
            }
            // 放到实体类中
            docs.add(searchHit.getContent());
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("docs", docs);
        resultMap.put("total", (int) search.getTotalHits());

        HttpServletRequest request = SpringUtil.getRequest();
        if (request != null) {
            request.setAttribute(ConstUtil.LIST_MODE, ConstUtil.LIST_MODE_FULLTEXT_SEARCH);
        }
        return resultMap;
    }
}
